/*
 * Copyright (c) Extreme Vision Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef EV_BASE_MODEL_H
#define EV_BASE_MODEL_H

#include <dlfcn.h>
#include "evdeploy/utils/json/json.h"

#define CREATE_INFER_INS(ENGINE) extern "C" void* create_infer_ins(){return new ENGINE;}
#define DESTROY_INFER_INS(ENGINE) extern "C" void destroy_infer_ins(void* ins){ENGINE* t_ins = (ENGINE*) ins ; delete t_ins;}


typedef void* (CREATE_INFER_INS)();
typedef void  (DESTROY_INFER_INS)(void*);

#include "evdeploy/core/ev_common_data.h"

namespace ev
{

class EVBaseModel
{
    public:

        EVBaseModel()
        {
            
        }
    
        virtual ~EVBaseModel()
        {
            ;
        }
        
        //load model and initization
        virtual EVStatus Init(const char* net, void** config) = 0;

        //relsease resource
        virtual EVStatus UnInit() = 0;

        //run optimize, like tensorrt optimize
        virtual EVStatus OptimizeModel(const char* model_name) = 0;
        
        //run inference
        virtual EVStatus Infer(EVModelData* in, EVModelData* out) = 0;

        virtual EVStatus SetIO(const std::vector<std::string>& inputs, const std::vector<std::string>& outputs) = 0;


    protected:
        bool m_init_flag = false;
};

class EVBaseModelFactory
{
    
    public:
        EVBaseModelFactory(std::string lib_name):m_lib_name(lib_name)
        {
            InitResource();
        }
        EVBaseModelFactory()
        {
            InitResource();
        }
        virtual ~EVBaseModelFactory()
        {        
            if(m_product_source != nullptr)
            {
                dlclose(m_product_source);
            }
        }

        virtual void* CreateProduct(const std::string& property)
        {
            void* ins = nullptr;
            if(m_product_producer != nullptr)
            {
                ins = m_product_producer();
            }
            return ins;
        }        

        virtual void DestroyProduct(void* ins)
        {
            m_product_destroyer(ins);
        }        

        virtual void InitResource()
        {
            m_product_source = dlopen(m_lib_name.c_str(), RTLD_LAZY);
            if(m_product_source == nullptr)
            {
                EVLOG(ERROR) << " failed to open " << m_lib_name << " " << dlerror();
            }
            
            m_product_producer = (CREATE_INFER_INS*) dlsym(m_product_source, "create_infer_ins");
            if(m_product_producer == nullptr)
            {
                EVLOG(ERROR) <<  " failed to parse symbol " <<  dlerror();
            }
                    
            m_product_destroyer = (DESTROY_INFER_INS*) dlsym(m_product_source, "destroy_infer_ins");
            if(m_product_destroyer == nullptr)
            {
                EVLOG(ERROR) << " failed to parse symbol " <<  dlerror();
            }
        }
    
    public:
        std::string m_lib_name = "";
        CREATE_INFER_INS*  m_product_producer = nullptr;
        DESTROY_INFER_INS* m_product_destroyer = nullptr;
        void* m_product_source = nullptr;
};

}//end namespace ev
#endif